﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;

namespace CopyrightLib
{
    /// <summary>
    /// Ричтекстбокс, который умеет сохраняться в битмап
    /// </summary>
    public class RichTextBoxPrintCtrl : RichTextBox
    {
        //Convert the unit used by the .NET framework (1/100 inch)
        //and the unit used by Win32 API calls (twips 1/1440 inch)

        private const double anInch = 14.4;

        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct CHARRANGE
        {
            public int cpMin; //First character of range (0 for start of doc)
            public int cpMax; //Last character of range (-1 for end of doc)
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct FORMATRANGE
        {
            public IntPtr hdc; //Actual DC to draw on
            public IntPtr hdcTarget; //Target DC for determining text formatting
            public RECT rc; //Region of the DC to draw to (in twips)
            public RECT rcPage; //Region of the whole DC (page size) (in twips)
            public CHARRANGE chrg; //Range of text to draw (see earlier declaration)
        }

        private const int WM_USER = 0x0400;

        private const int EM_FORMATRANGE = WM_USER + 57;

        [DllImport("USER32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

        // Render the contents of the RichTextBox for printing
        // Return the last character printed + 1 (printing start from this point for next page)
        public int Print(int charFrom, int charTo, Graphics gr, Rectangle bounds)
        {
            //Calculate the area to render and print

            RECT rectToPrint;
            rectToPrint.Top = 0;// (int)(bounds.Top * anInch);
            rectToPrint.Bottom = (int)(bounds.Height * anInch);// (int)(bounds.Bottom * anInch);
            rectToPrint.Left = 0;// (int)(bounds.Left * anInch);
            rectToPrint.Right = (int)(bounds.Width * anInch);// (int)(bounds.Right * anInch);

            //Calculate the size of the page
            RECT rectPage;
            rectPage.Top = 0;//(int)(bounds.Top * anInch);
            rectPage.Bottom = (int)(gr.ClipBounds.Height * anInch);//(int)(bounds.Bottom * anInch);
            rectPage.Left = 0;//(int)(bounds.Left * anInch);
            rectPage.Right = (int)(gr.ClipBounds.Right * anInch);//(int)(bounds.Right * anInch);

            IntPtr hdc = gr.GetHdc();

            FORMATRANGE fmtRange;
            fmtRange.chrg.cpMax = charTo; //Indicate character from to character to
            fmtRange.chrg.cpMin = charFrom;
            fmtRange.hdc = hdc; //Use the same DC for measuring and rendering
            fmtRange.hdcTarget = hdc; //Point at printer hDC
            fmtRange.rc = rectToPrint; //Indicate the area on page to print
            fmtRange.rcPage = rectPage; //Indicate size of page

            IntPtr res = IntPtr.Zero;
            IntPtr wparam = IntPtr.Zero;
            wparam = new IntPtr(1);

            //Get the pointer to the FORMATRANGE structure in memory
            IntPtr lparam = IntPtr.Zero;
            lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));

            Marshal.StructureToPtr(fmtRange, lparam, false);

            //Send the rendered data for printing
            res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam);

            //Free the block of memory allocated
            Marshal.FreeCoTaskMem(lparam);

            //Release the device context handle obtained by a previous call
            gr.ReleaseHdc(hdc);

            //Return last + 1 character printer
            return res.ToInt32();
        }
    }
}
